package rpc_netty.server;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rpc_netty.server.ServiceProvider.DefaultServiceProvider;
import rpc_1.Service.RpcException;
import rpc_netty.Annotation.ReflectUtil;
import rpc_netty.Annotation.Service;
import rpc_netty.Annotation.ServiceScan;
import rpc_netty.interfaces.RpcServer;

import rpc_1.interfaces.ServiceRegisrty;

import java.net.InetSocketAddress;
import java.util.Set;


public abstract class AbstractRpcServer implements RpcServer {

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    protected String host;
    protected int port;

    protected ServiceRegisrty serviceRegistry;
    protected DefaultServiceProvider serviceProvider;

    //扫描服务类所在的包，并自动注册
    public void scanServices() throws RpcException {
        //找到使用main函数启动服务器的类，这个类上面有serviceScan注解
        String mainClassName = ReflectUtil.getStackTrace();
        Class<?> startClass;
        try {
            startClass = Class.forName(mainClassName);
            if(!startClass.isAnnotationPresent(ServiceScan.class)) {
                logger.error("启动类缺少 @ServiceScan 注解");
                throw new RpcException("lack of annotation ");
            }
        } catch (ClassNotFoundException e) {
            logger.error("出现未知错误");
            throw new RpcException("UNKNOWN_ERROR");
        }
        //根据注解的值，获得service所在的包
        String basePackage = startClass.getAnnotation(ServiceScan.class).value();
        //默认是main函数启动服务器的类所在的包下面的impl包，在该项目中，就是server/impl包
        if("".equals(basePackage)) {
            basePackage = mainClassName.substring(0, mainClassName.lastIndexOf("."));
        }
        basePackage+=".impl";
        logger.info("servicePackage:{}",basePackage);
        //获取这个包下面的所有类
        Set<Class<?>> classSet = ReflectUtil.getClasses(basePackage);
        for(Class<?> clazz : classSet) {
            //如果有service注解，那么就把这个类生成实例，并且把它和相应的方法注册到provider和注册中心
            if(clazz.isAnnotationPresent(Service.class)) {
                String serviceName = clazz.getAnnotation(Service.class).name();
                Object obj;
                try {
                    //创建实例
                    obj = clazz.newInstance();
                } catch (InstantiationException | IllegalAccessException e) {
                    logger.error("创建 " + clazz + " 时有错误发生");
                    continue;
                }
                if("".equals(serviceName)) {
                    Class<?>[] interfaces = clazz.getInterfaces();
                    for (Class<?> oneInterface: interfaces){
                        publishService(obj,oneInterface.getCanonicalName());
                    }
                } else {
                    publishService(obj,serviceName);
                }
            }
        }
    }

    @Override
    public <T> void publishService(T service, String serviceName)  {
        try {
            serviceProvider.provide(service);
        } catch (RpcException e) {
            e.printStackTrace();
        }
        serviceRegistry.register(serviceName, new InetSocketAddress(host, port));
    }

}
